/*
 * This is written by Lulu Han.
 * E-mail: locomotive_crypto@163.com
 */

#include "sec_set.h"

SecSet::CloudA::CloudA(const PrivateKey& pri): m_dec(pri), m_mulA(pri){
	// ...
}

void SecSet::CloudA::set_vlen(long vlens){
	m_nlens = NTL::NumBits(m_dec.GetN()) - 1;
	m_vlens = vlens;
}

void SecSet::CloudA::dec_reenc(const NTL::ZZ& nca, const NTL::ZZ& ncb, NTL::ZZ& cmul){
	m_mulA.dec_reenc(nca, ncb, cmul);
}

void SecSet::CloudA::dec_gen_beta(const NTL::ZZ& ct, NTL::ZZ& cbeta){
	NTL::ZZ t, beta;
	
	m_dec.Decrypt(ct, t);
	
	if(t < m_dec.GetN() / 2){
		beta = 0;
	}
	else{
		beta = 1;
	}
	
	m_dec.Encrypt(beta, cbeta);
}

////////////////////////////////////////////////////////////////////////////////////////

SecSet::CloudB::CloudB(const PublicKey& pub): m_enc(pub), m_mulB(pub){
	// ...
}

void SecSet::CloudB::set_vlen(long vlens){
	m_nlens = NTL::NumBits(m_enc.GetN()) - 1;
	m_vlens = vlens;
}

void SecSet::CloudB::calc_sub(const NTL::ZZ& cx, const NTL::ZZ& cy){
	NTL::ZZ t;
	
	m_enc.HE_Mul_Const(cx, m_enc.GetN() - 1, t);
	m_enc.HE_Add_Cipher(t, cy, m_d);
}

void SecSet::CloudB::gen_two_ciphers(NTL::ZZ& nca, NTL::ZZ& ncb){
	m_mulB.gen_two_ciphers(m_d, m_d, nca, ncb);
}

void SecSet::CloudB::calc_expr(const NTL::ZZ& cmul, NTL::ZZ& ct){
	NTL::ZZ r1, r2, r;
	
	r1 = NTL::RandomLen_ZZ(m_nlens/2 - 2*m_vlens - 1);
	r2 = NTL::RandomLen_ZZ(m_nlens/2 - 2*m_vlens - 1);
	
	if(r2 > r1){
		r = r1;
		r1 = r2;
		r2 = r;
	}
	
	NTL::ZZ h, r1h, s;
	
	m_mulB.gen_mul(cmul, h);
	
	m_enc.HE_Mul_Const(h, r1, r1h);
	
	m_alpha =  NTL::RandomLen_ZZ(8) % 2;
	
	if(m_alpha == 0){
		m_enc.Encrypt(r2, s);
		m_enc.HE_Mul_Const(s, m_enc.GetN() - 1, s); // s = -r2
		m_enc.HE_Add_Cipher(r1h, s, ct); // t = r1*(x-y)^2 - r2
	}
	else{
		m_enc.Encrypt(r2, s);
		m_enc.HE_Mul_Const(r1h, m_enc.GetN() - 1, r1h); // r1h = -r1*(x-y)^2
		m_enc.HE_Add_Cipher(r1h, s, ct); // t = r2 - r1*(x-y)^2 
	}
	
}

void SecSet::CloudB::gen_res(const NTL::ZZ& cbeta, NTL::ZZ& res){
	NTL::ZZ cone, neg;
	
	m_enc.Encrypt(NTL::ZZ(1), cone);
	
	if(m_alpha == 0){
		res = cbeta;
	}
	else{
		m_enc.HE_Mul_Const(cbeta, m_enc.GetN() - 1, neg);
		m_enc.HE_Add_Cipher(cone, neg, res);
	}
}
